package client;

import java.io.IOException;
import java.net.UnknownHostException;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.security.cert.X509Certificate;

public class ClientAuthenticator extends Authenticator {
	private SSLSocket socket;
	private boolean connectionFailed;

	/**
	 * 
	 * @param password
	 *            is the password to both the keystore and the truststore
	 * @param keyStorePath
	 *            is the path relative to this program where the keystore is
	 * @param trustStorePath
	 *            is the path relative to this program where the truststore is
	 * @param host
	 *            is the address to the host
	 * @param port
	 *            is the port to use for this program on this computer
	 */
	public ClientAuthenticator(String password, String keyStorePath,
			String trustStorePath, String host, int port) {
		SSLSocketFactory socketFactory = null;
		try {
			SSLContext context = getContext(password, keyStorePath,
					trustStorePath);
			socketFactory = context.getSocketFactory();
		} catch (Exception e) {
			connectionFailed = true;
			System.out.println("Incorrect password, unvalid keystore or unvalid truststore.");
			
			return;
		}

		try {
			socket = (SSLSocket) socketFactory.createSocket(host, port);
		} catch (UnknownHostException e) {
			System.out.println("Unable to create socket. Unknown host.");
			connectionFailed = true;
		} catch (IOException e) {
			System.out.println("Unable to create socket.");
			connectionFailed = true;
		}
	}

	public boolean connectionFailed() {
		return connectionFailed;
	}

	/**
	 * Use this to set up the connection.
	 * 
	 * @return a socket where data can be sent to the server
	 */
	public SSLSocket validateServerConnection() {
		/*
		 * send http request
		 * 
		 * Before any application data is sent or received, the SSL socket will
		 * do SSL handshaking first to set up the security attributes.
		 * 
		 * SSL handshaking can be initiated by either flushing data down the
		 * pipe, or by starting the handshaking by hand.
		 * 
		 * Handshaking is started manually in this example because PrintWriter
		 * catches all IOExceptions (including SSLExceptions), sets an internal
		 * error flag, and then returns without rethrowing the exception.
		 * 
		 * Unfortunately, this means any error messages are lost, which caused
		 * lots of confusion for others using this code. The only way to tell
		 * there was an error is to call PrintWriter.checkError().
		 */
		try {
			socket.startHandshake();

			SSLSession session = socket.getSession();
			X509Certificate cert = (X509Certificate) session
					.getPeerCertificateChain()[0];
			String subject = cert.getSubjectDN().getName();
			if (getUserID(subject).equals("server")) {
				return socket;
			}

//			System.out.println("socket information");
//			System.out.println(socket);
//			System.out.println();
//			System.out.println("server's certificate information");
//			System.out.println(subject);
//			System.out.println();
			return null;
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
	}

}
